module cache (
    input clk,
    input resetn,
    
    //CPU and cache
    input        valid,
    input        op,
    input [ 7:0] index,
    input [19:0] tag,
    input [ 3:0] offset,
    input [ 3:0] wstrb,
    input [31:0] wdata,

    output        addr_ok,
    output        data_ok,
    output [31:0] rdata,

    //AXI and cache
    output        rd_req,
    output [ 2:0] rd_type,
    output [31:0] rd_addr,
    input         rd_rdy,
    input         ret_valid,
    input  [ 1:0] ret_last,
    input  [31:0] ret_data,

    output        wr_req,
    output [ 2:0] wr_type,
    output [31:0] wr_addr,
    output [ 3:0] wr_wstrb,
    output [127:0] wr_data,
    input         wr_rdy
);

//one hot state machine code
parameter IDLE    =  5'b00001;
parameter LOOKUP   = 5'b00010;
parameter MISS     = 5'b00100;
parameter REPLACE  = 5'b01000;
parameter REFILL   = 5'b10000;
parameter IDLE_W   = 2'b01;
parameter WRITE    = 2'b10;


//Tagv Sram(2)
wire        tagv_way0_en;
wire        tagv_way1_en;
wire        tagv_way0_we;
wire        tagv_way1_we;
wire [ 7:0] tagv_addr;
wire [20:0] tagv_way0_din;
wire [20:0] tagv_way0_dout;
wire [20:0] tagv_way1_din;
wire [20:0] tagv_way1_dout;

TAGV_RAM tagv_ram_way0(
    .clka    (clk),
    .addra   (tagv_addr),
    .ena     (tagv_way0_en),
    .wea     (tagv_way0_we),
    .dina    (tagv_way0_din),
    .douta   (tagv_way0_dout)
);

TAGV_RAM tagv_ram_way1(
    .clka    (clk),
    .addra   (tagv_addr),
    .ena     (tagv_way1_en),
    .wea     (tagv_way1_we),
    .dina    (tagv_way1_din),
    .douta   (tagv_way1_dout)
);

//Data sram(8)4
//en
wire data_way0_bank0_en;
wire data_way0_bank1_en;
wire data_way0_bank2_en;
wire data_way0_bank3_en;
wire data_way1_bank0_en;
wire data_way1_bank1_en;
wire data_way1_bank2_en;
wire data_way1_bank3_en;
//we
wire [3:0] data_way0_bank0_we;
wire [3:0] data_way0_bank1_we;
wire [3:0] data_way0_bank2_we;
wire [3:0] data_way0_bank3_we;
wire [3:0] data_way1_bank0_we;
wire [3:0] data_way1_bank1_we;
wire [3:0] data_way1_bank2_we;
wire [3:0] data_way1_bank3_we;
//addr
wire [7:0] data_addr;
//din
wire [31:0] data_way0_bank0_din;
wire [31:0] data_way0_bank1_din;
wire [31:0] data_way0_bank2_din;
wire [31:0] data_way0_bank3_din;
wire [31:0] data_way1_bank0_din;
wire [31:0] data_way1_bank1_din;
wire [31:0] data_way1_bank2_din;
wire [31:0] data_way1_bank3_din;
//dout
wire [31:0] data_way0_bank0_dout;
wire [31:0] data_way0_bank1_dout;
wire [31:0] data_way0_bank2_dout;
wire [31:0] data_way0_bank3_dout;
wire [31:0] data_way1_bank0_dout;
wire [31:0] data_way1_bank1_dout;
wire [31:0] data_way1_bank2_dout;
wire [31:0] data_way1_bank3_dout;

data_bank_ram data_ram_way0_bank0(
    .clka    (clk),
    .addra   (data_addr),
    .ena     (data_way0_bank0_en),
    .wea     (data_way0_bank0_we),
    .dina    (data_way0_bank0_din),
    .douta   (data_way0_bank0_dout)
);

data_bank_ram data_ram_way0_bank1(
    .clka    (clk),
    .addra   (data_addr),
    .ena     (data_way0_bank1_en),
    .wea     (data_way0_bank1_we),
    .dina    (data_way0_bank1_din),
    .douta   (data_way0_bank1_dout)
);

data_bank_ram data_ram_way0_bank2(
    .clka    (clk),
    .addra   (data_addr),
    .ena     (data_way0_bank2_en),
    .wea     (data_way0_bank2_we),
    .dina    (data_way0_bank2_din),
    .douta   (data_way0_bank2_dout)
);

data_bank_ram data_ram_way0_bank3(
    .clka    (clk),
    .addra   (data_addr),
    .ena     (data_way0_bank3_en),
    .wea     (data_way0_bank3_we),
    .dina    (data_way0_bank3_din),
    .douta   (data_way0_bank3_dout)
);

data_bank_ram data_ram_way1_bank0(
    .clka    (clk),
    .addra   (data_addr),
    .ena     (data_way1_bank0_en),
    .wea     (data_way1_bank0_we),
    .dina    (data_way1_bank0_din),
    .douta   (data_way1_bank0_dout)
);

data_bank_ram data_ram_way1_bank1(
    .clka    (clk),
    .addra   (data_addr),
    .ena     (data_way1_bank1_en),
    .wea     (data_way1_bank1_we),
    .dina    (data_way1_bank1_din),
    .douta   (data_way1_bank1_dout)
);

data_bank_ram data_ram_way1_bank2(
    .clka    (clk),
    .addra   (data_addr),
    .ena     (data_way1_bank2_en),
    .wea     (data_way1_bank2_we),
    .dina    (data_way1_bank2_din),
    .douta   (data_way1_bank2_dout)
);

data_bank_ram data_ram_way1_bank3(
    .clka    (clk),
    .addra   (data_addr),
    .ena     (data_way1_bank3_en),
    .wea     (data_way1_bank3_we),
    .dina    (data_way1_bank3_din),
    .douta   (data_way1_bank3_dout)
);

reg d_way0 [255:0];
reg d_way1 [255:0];

reg [4:0] state;
reg [4:0] next_state;
reg [1:0] wstate;
reg [1:0] wnext_state;

reg rb_op;
reg [ 7:0] rb_index;
reg [19:0] rb_tag;
reg [ 3:0] rb_offset;
reg [ 3:0] rb_wstrb;
reg [31:0] rb_wdata;

always @(posedge clk) begin
    if(~resetn) begin
        rb_op     <= 1'b0;
        rb_index  <= 8'b0;
        rb_tag    <= 20'b0;
        rb_offset <= 4'b0;
        rb_wstrb  <= 4'b0;
        rb_wdata  <= 32'b0;

    end
    else if(valid & addr_ok) begin
        rb_op     <= op;
        rb_index  <= index;
        rb_tag    <= tag;
        rb_offset <= offset;
        rb_wstrb  <= wstrb;
        rb_wdata  <= wdata;
    end
end

wire way0_v;
wire way1_v;
wire [19:0] way0_tag;
wire [19:0] way1_tag;
wire way0_hit;
wire way1_hit;
wire cache_hit;

assign way0_hit  = way0_v && (way0_tag == rb_tag);
assign way1_hit  = way1_v && (way1_tag == rb_tag);
assign cache_hit = way0_hit || way1_hit;

assign way0_v   = tagv_way0_dout[20];
assign way1_v   = tagv_way1_dout[20];
assign way0_tag = tagv_way0_dout[19:0];
assign way1_tag = tagv_way1_dout[19:0];

wire [127:0] way0_data;
wire [127:0] way1_data;
wire [ 31:0] way0_load_word;
wire [ 31:0] way1_load_word;
wire [ 31:0] load_res;
wire [127:0] replace_data;

assign way0_data = {{8'hff,data_way0_bank3_dout[23:0]}, data_way0_bank2_dout, data_way0_bank1_dout, data_way0_bank0_dout};
assign way1_data = {{8'hff,data_way1_bank3_dout[23:0]}, data_way1_bank2_dout, data_way1_bank1_dout, data_way1_bank0_dout};

assign way0_load_word = way0_data[rb_offset[3:2]*32 +: 32];
assign way1_load_word = way1_data[rb_offset[3:2]*32 +: 32];
assign load_res = {32{way0_hit}}   & way0_load_word |
                  {32{way1_hit}}   & way1_load_word;

assign rdata = ((state==LOOKUP) && cache_hit) ? load_res : 
			   ((state == REFILL) && recv_last)? rd_way_rdata: 32'b0;

reg feedback;
reg [7:0] lfsr;
reg [7:0] lfsr_next;
reg       rp_way;

always @(posedge clk) begin
    if(~resetn) begin
        lfsr <= 8'b0;
    end
    else begin
        lfsr <= lfsr_next;
    end
end

always @(*) begin
    feedback      = lfsr[7] ^ ~(|lfsr[6:0]);
    lfsr_next[7]  = lfsr[6];
    lfsr_next[6]  = lfsr[5] ^ feedback;
    lfsr_next[5]  = lfsr[4];
    lfsr_next[4]  = lfsr[3] ^ feedback;
    lfsr_next[3]  = lfsr[2] ^ feedback;
    lfsr_next[2]  = lfsr[1] ^ feedback;
    lfsr_next[1]  = lfsr[0];
    lfsr_next[0]  = feedback;
end

always @(posedge clk) begin
    if(~resetn) begin
        rp_way <= 1'b0;
    end else begin
        rp_way <= lfsr[0];
    end
end

reg         rp_way_v;
reg         rp_way_d;
reg [ 19:0] rp_way_tag;
reg [127:0] rp_way_data;

wire way0_d;
wire way1_d;
assign way0_d = d_way0[rb_index];
assign way1_d = d_way1[rb_index];

always @(posedge clk) begin
    if(~resetn) begin
        rp_way_v    <= 1'b0;
        rp_way_d    <= 1'b0;
        rp_way_tag  <= 20'b0;
        rp_way_data <= 128'b0;
    end
    else if((state == LOOKUP) && ~cache_hit) begin
        rp_way_v    <= rp_way? way1_v    : way0_v;
        rp_way_d    <= rp_way? way1_d    : way0_d;
        rp_way_tag  <= rp_way? way1_tag  : way0_tag;
        rp_way_data <= rp_way? way1_data : way0_data;
    end
end

reg recv_last;
reg [1:0] counter;
reg [127:0] rd_way_data;

always @(posedge clk) begin
	if (!resetn)
		recv_last <= 1'b0;
	else begin
		if(state == REFILL) begin
            if (rd_req && ret_valid && counter == 2'b11)
				recv_last <= 1'b1;
			else
				recv_last <= recv_last;
		end
		else
			recv_last <= 1'b0;
	end
end
always @(posedge clk) begin
	if (!resetn)
		counter <= 2'b0;
	else begin
		if (state == REFILL) begin
			if (rd_req && ret_valid)
				counter <= counter + 2'd1;
			else
				counter <= counter;
		end
		else
			counter <= 2'b0;
	end
end
always @(posedge clk) begin
	if (state == REFILL && rd_req && ret_valid) begin
        case(counter)
			2'b00:
				rd_way_data[31:0] <= ret_data;
			2'b01:
				rd_way_data[63:32] <= ret_data;
			2'b10:
				rd_way_data[95:64] <= ret_data;
			2'b11:
				rd_way_data[127:96] <= ret_data;
        endcase
	end
end

wire [31:0] rd_way_data_bank0;
wire [31:0] rd_way_data_bank1;
wire [31:0] rd_way_data_bank2;
wire [31:0] rd_way_data_bank3;
wire [31:0] rd_way_wdata_bank0;
wire [31:0] rd_way_wdata_bank1;
wire [31:0] rd_way_wdata_bank2;
wire [31:0] rd_way_wdata_bank3;
wire [31:0] rd_way_rdata;

assign rd_way_data_bank0 = rd_way_data[31:0];
assign rd_way_data_bank1 = rd_way_data[63:32];
assign rd_way_data_bank2 = rd_way_data[95:64];
assign rd_way_data_bank3 = rd_way_data[127:96];
assign rd_way_wdata_bank0[ 7: 0] = (rb_op && rb_offset[3:2] == 2'b00 && rb_wstrb[0]) ? rb_wdata[ 7: 0] : rd_way_data_bank0[ 7: 0];
assign rd_way_wdata_bank0[15: 8] = (rb_op && rb_offset[3:2] == 2'b00 && rb_wstrb[1]) ? rb_wdata[15: 8] : rd_way_data_bank0[15: 8];
assign rd_way_wdata_bank0[23:16] = (rb_op && rb_offset[3:2] == 2'b00 && rb_wstrb[2]) ? rb_wdata[23:16] : rd_way_data_bank0[23:16];
assign rd_way_wdata_bank0[31:24] = (rb_op && rb_offset[3:2] == 2'b00 && rb_wstrb[3]) ? rb_wdata[31:24] : rd_way_data_bank0[31:24];
assign rd_way_wdata_bank1[ 7: 0] = (rb_op && rb_offset[3:2] == 2'b01 && rb_wstrb[0]) ? rb_wdata[ 7: 0] : rd_way_data_bank1[ 7: 0];
assign rd_way_wdata_bank1[15: 8] = (rb_op && rb_offset[3:2] == 2'b01 && rb_wstrb[1]) ? rb_wdata[15: 8] : rd_way_data_bank1[15: 8];
assign rd_way_wdata_bank1[23:16] = (rb_op && rb_offset[3:2] == 2'b01 && rb_wstrb[2]) ? rb_wdata[23:16] : rd_way_data_bank1[23:16];
assign rd_way_wdata_bank1[31:24] = (rb_op && rb_offset[3:2] == 2'b01 && rb_wstrb[3]) ? rb_wdata[31:24] : rd_way_data_bank1[31:24];
assign rd_way_wdata_bank2[ 7: 0] = (rb_op && rb_offset[3:2] == 2'b10 && rb_wstrb[0]) ? rb_wdata[ 7: 0] : rd_way_data_bank2[ 7: 0];
assign rd_way_wdata_bank2[15: 8] = (rb_op && rb_offset[3:2] == 2'b10 && rb_wstrb[1]) ? rb_wdata[15: 8] : rd_way_data_bank2[15: 8];
assign rd_way_wdata_bank2[23:16] = (rb_op && rb_offset[3:2] == 2'b10 && rb_wstrb[2]) ? rb_wdata[23:16] : rd_way_data_bank2[23:16];
assign rd_way_wdata_bank2[31:24] = (rb_op && rb_offset[3:2] == 2'b10 && rb_wstrb[3]) ? rb_wdata[31:24] : rd_way_data_bank2[31:24];
assign rd_way_wdata_bank3[ 7: 0] = (rb_op && rb_offset[3:2] == 2'b11 && rb_wstrb[0]) ? rb_wdata[ 7: 0] : rd_way_data_bank3[ 7: 0];
assign rd_way_wdata_bank3[15: 8] = (rb_op && rb_offset[3:2] == 2'b11 && rb_wstrb[1]) ? rb_wdata[15: 8] : rd_way_data_bank3[15: 8];
assign rd_way_wdata_bank3[23:16] = (rb_op && rb_offset[3:2] == 2'b11 && rb_wstrb[2]) ? rb_wdata[23:16] : rd_way_data_bank3[23:16];
assign rd_way_wdata_bank3[31:24] = (rb_op && rb_offset[3:2] == 2'b11 && rb_wstrb[3]) ? rb_wdata[31:24] : rd_way_data_bank3[31:24];
assign rd_way_rdata = (rb_offset[3:2] == 2'b00) ? rd_way_data_bank0 : 
                      (rb_offset[3:2] == 2'b01) ? rd_way_data_bank1 :
                      (rb_offset[3:2] == 2'b10) ? rd_way_data_bank2 : 
                      (rb_offset[3:2] == 2'b11) ? rd_way_data_bank3: 32'b0;

reg         wb_hit_way;
reg [ 7:0]  wb_index;
reg [ 3:0]  wb_offset;
reg [ 3:0]  wb_wstrb;
reg [31:0]  wb_wdata;

always @(posedge clk) begin
    if(~resetn) begin
        wb_hit_way <= 1'b0;
        wb_index   <= 8'b0;
        wb_offset  <= 4'b0;
        wb_wstrb   <= 4'b0;
        wb_wdata   <= 32'b0;
    end
    else if(cache_hit) begin
        wb_hit_way <= way0_hit? 1'b0:1'b1;
        wb_index   <= rb_index;
        wb_offset  <= rb_offset;
        wb_wstrb   <= rb_wstrb;
        wb_wdata   <= rb_wdata;
    end
end

genvar i;
generate for(i = 0; i < 256; i = i + 1) begin: gen_way0
    always @(posedge clk) begin
        if(~resetn) begin
            d_way0[i] <= 1'b0;
        end
    end
end endgenerate

genvar j;
generate for(j = 0; j < 256; j = j + 1) begin: gen_way1
    always @(posedge clk) begin
        if(~resetn) begin
            d_way1[j] <= 1'b0;
        end
    end
end endgenerate

always @(posedge clk) begin
    if(wstate == WRITE && ~wb_hit_way) begin
        d_way0[wb_index] <= 1'b1;
    end
    else if(state == REFILL && recv_last && ~rp_way) begin
        d_way0[rb_index] <= rb_op;          
    end
end

always @(posedge clk) begin
    if(wstate == WRITE && wb_hit_way) begin
        d_way1[wb_index] <= 1'b1;
    end
    else if(state == REFILL && recv_last && rp_way) begin
        d_way1[rb_index] <= rb_op;         
    end
end

assign tagv_way0_en  = (state == IDLE && valid && addr_ok) || (state == REFILL && recv_last && ~rp_way);
assign tagv_way1_en  = (state == IDLE && valid && addr_ok) || (state == REFILL && recv_last &&  rp_way);
assign tagv_way0_we = (state == REFILL && recv_last && ~rp_way);
assign tagv_way1_we = (state == REFILL && recv_last &&  rp_way);
assign tagv_way0_din = {1'b1, rb_tag};          //valid set 1
assign tagv_way1_din = {1'b1, rb_tag};          //valid set 1
assign tagv_addr     = (state == IDLE && valid && addr_ok)? index: rb_index; //Note: when idle & addr_ok & valid, index does not update!

/*data ram*/
assign data_way0_bank0_en = (state == IDLE && valid && addr_ok) || (state == REFILL && recv_last && ~rp_way)
                        || (wstate == WRITE && wb_offset[3:2] == 2'b00 && ~wb_hit_way);
assign data_way0_bank1_en = (state == IDLE && valid && addr_ok) || (state == REFILL && recv_last && ~rp_way)
                        || (wstate == WRITE && wb_offset[3:2] == 2'b01 && ~wb_hit_way);
assign data_way0_bank2_en = (state == IDLE && valid && addr_ok) || (state == REFILL && recv_last && ~rp_way)
                        || (wstate == WRITE && wb_offset[3:2] == 2'b10 && ~wb_hit_way);
assign data_way0_bank3_en = (state == IDLE && valid && addr_ok) || (state == REFILL && recv_last && ~rp_way)
                        || (wstate == WRITE && wb_offset[3:2] == 2'b11 && ~wb_hit_way);
assign data_way1_bank0_en = (state == IDLE && valid && addr_ok) || (state == REFILL && recv_last && rp_way)
                        || (wstate == WRITE && wb_offset[3:2] == 2'b00 && wb_hit_way);
assign data_way1_bank1_en = (state == IDLE && valid && addr_ok) || (state == REFILL && recv_last && rp_way)
                        || (wstate == WRITE && wb_offset[3:2] == 2'b01 && wb_hit_way);
assign data_way1_bank2_en = (state == IDLE && valid && addr_ok) || (state == REFILL && recv_last && rp_way)
                        || (wstate == WRITE && wb_offset[3:2] == 2'b10 && wb_hit_way);
assign data_way1_bank3_en = (state == IDLE && valid && addr_ok) || (state == REFILL && recv_last && rp_way)
                        || (wstate == WRITE && wb_offset[3:2] == 2'b11 && wb_hit_way);

assign data_way0_bank0_we = (wstate == WRITE && wb_offset[3:2] == 2'b00 && ~wb_hit_way)? wb_wstrb:
                            (state == REFILL && recv_last && ~rp_way)? 4'b1111: 4'b0000;
assign data_way0_bank1_we = (wstate == WRITE && wb_offset[3:2] == 2'b01 && ~wb_hit_way)? wb_wstrb:
                            (state == REFILL && recv_last && ~rp_way)? 4'b1111: 4'b0000;
assign data_way0_bank2_we = (wstate == WRITE && wb_offset[3:2] == 2'b10 && ~wb_hit_way)? wb_wstrb:
                            (state == REFILL && recv_last && ~rp_way)? 4'b1111: 4'b0000;
assign data_way0_bank3_we = (wstate == WRITE && wb_offset[3:2] == 2'b11 && ~wb_hit_way)? wb_wstrb:
                            (state == REFILL && recv_last && ~rp_way)? 4'b1111: 4'b0000;
assign data_way1_bank0_we = (wstate == WRITE && wb_offset[3:2] == 2'b00 && wb_hit_way)? wb_wstrb:
                            (state == REFILL && recv_last && rp_way)? 4'b1111: 4'b0000;
assign data_way1_bank1_we = (wstate == WRITE && wb_offset[3:2] == 2'b01 && wb_hit_way)? wb_wstrb:
                            (state == REFILL && recv_last && rp_way)? 4'b1111: 4'b0000;
assign data_way1_bank2_we = (wstate == WRITE && wb_offset[3:2] == 2'b10 && wb_hit_way)? wb_wstrb:
                            (state == REFILL && recv_last && rp_way)? 4'b1111: 4'b0000;
assign data_way1_bank3_we = (wstate == WRITE && wb_offset[3:2] == 2'b11 && wb_hit_way)? wb_wstrb:
                          (state == REFILL && recv_last && rp_way)? 4'b1111: 4'b0000;
//assign data_way1_bank3_we = (wb_offset[3:2] == 2'b11 && wb_hit_way)? wb_wstrb:
//                            (state == REFILL && recv_last && rp_way)? 4'b1111: 4'b0000;
    
assign data_way0_bank0_din = (wstate == WRITE)? wb_wdata: rd_way_wdata_bank0;
assign data_way0_bank1_din = (wstate == WRITE)? wb_wdata: rd_way_wdata_bank1;
assign data_way0_bank2_din = (wstate == WRITE)? wb_wdata: rd_way_wdata_bank2;
assign data_way0_bank3_din = (wstate == WRITE)? wb_wdata: rd_way_wdata_bank3;
assign data_way1_bank0_din = (wstate == WRITE)? wb_wdata: rd_way_wdata_bank0;
assign data_way1_bank1_din = (wstate == WRITE)? wb_wdata: rd_way_wdata_bank1;
assign data_way1_bank2_din = (wstate == WRITE)? wb_wdata: rd_way_wdata_bank2;
assign data_way1_bank3_din = (wstate == WRITE)? wb_wdata: rd_way_wdata_bank3;

assign data_addr = (wstate == WRITE)? wb_index:
                   (state  == IDLE && valid && addr_ok)? index: rb_index;


//Write Buffer State Machine
always @(posedge clk) begin
    if(~resetn) begin
        wstate <= IDLE_W;
    end begin
        wstate <= wnext_state;
    end
end
always @(*) begin
	case(wstate)
	IDLE_W:
		if ((state == LOOKUP) && cache_hit && (rb_op == 1'b1)) begin
			wnext_state = WRITE;
		end
		else begin
			wnext_state = IDLE_W;
		end
	WRITE:
		if ((state == LOOKUP) && cache_hit && (rb_op == 1'b1)) begin
			wnext_state = WRITE;
		end
		else begin
			wnext_state = IDLE_W;
		end
	default:
			wnext_state = IDLE_W;
	endcase
end
//Main State Machine
always @(posedge clk) begin
    if(~resetn) begin
        state <= IDLE_W;
    end begin
        state <= next_state;
    end
end
always @(*) begin
	case(state)
	IDLE:
		if (valid && addr_ok) begin
			next_state = LOOKUP;
		end
		else begin
			next_state = IDLE;
		end
	LOOKUP:
        if (cache_hit) begin
			next_state = IDLE;
		end
		else begin
			next_state = MISS;
		end
	MISS:
		if (wr_rdy==1'b1) begin
			next_state = REPLACE;
		end
		else begin
			next_state = MISS;
		end
    REPLACE:
		if (rd_rdy==1'b1) begin
			next_state = REFILL;
		end
		else begin
			next_state = REPLACE;
		end
	REFILL:
		if (recv_last==1'b1) begin
			next_state = IDLE;
		end
		else begin 
			next_state = REFILL;
		end
	default:
			next_state = IDLE;
	endcase
end

assign addr_ok = (state == IDLE) && valid && (wstate == IDLE_W);
assign data_ok = (state == LOOKUP) && cache_hit || (state == REFILL) && recv_last;
assign rd_req = (state == REFILL) && !recv_last;
assign rd_type = 3'b010; //?
assign rd_addr = {rb_tag, rb_index, counter, 2'b0};

reg wr_req_r;
always @(posedge clk) begin
    if (!resetn) begin
        wr_req_r <= 1'b0;
    end
    else if (state == MISS && wr_rdy && rp_way_d && rp_way_v) begin
        wr_req_r <= 1'b1;
    end
    else if (wr_req_r == 1'b1) begin
        wr_req_r <= 1'b0;
    end
end
assign wr_req = wr_req_r;
assign wr_type = 3'b100; //?
assign wr_addr = {rp_way_tag, rb_index, 4'b0};
assign wr_wstrb = 4'b1;
assign wr_data = rp_way_data;

endmodule //cache